package com.Team7.util;

import com.Team7.domain.Item;
import com.Team7.domain.OFFile;
import com.Team7.domain.Pointer;
import com.Team7.domain.SearchedFile;
import com.Team7.factory.DiskFactory;

import java.nio.file.attribute.DosFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.zip.CheckedOutputStream;

import static com.Team7.util.DiskUtil.getFreeBlock;

public class FileUtil {

    public static Pointer getWirterPoniter(byte[][] disk,SearchedFile searchedFile){
        Pointer writer=new Pointer();

        int cur=(int) searchedFile.getItem().getAttr()[6];
        int next;
        int j=0;
        while (true){
            if(DiskFactory.getDisk()[cur][j++]==35){
                break;
            }
            if(j==64){
                j=0;
                next=disk[cur/64][cur%64];
                cur=next;
            }
        }
        writer.setDnum(cur);
        writer.setBnum(j-1);

        return writer;
    }

    /**
     * @Author: ginenn
     * @Date: 2019/11/30 21:06
     * @Description: 根据文件的对路径，返回文件所在的行号，列号，和文件本身的字节，用SearchedFile封装
     */
    public static SearchedFile findPathSearchedFile(byte [][] disk, String path){
        String [] str = path.split("/");
        int pos = findDiskPos(disk,str,0,2);
        for(int i = 0; i < 64; i += 8){
            int ok = 1;
            for(int j=0; j < str[str.length-1].length(); j++){
                if((byte)str[str.length-1].charAt(j) != disk[pos][i+j]) ok = 0;
            }
            if(ok == 1){
                Item item = new Item();
                byte [] attr = new byte[8];
                for(int j = 0; j < 8; j++){
                    attr[j] = disk[pos][j+i];
                }
                item.setAttr(attr);
                SearchedFile searchedFile = new SearchedFile(pos,i/8,item);
                return searchedFile;
            }
        }
        return null;
    }

    /**
     * @Author: Space
     * @Date: 2019/11/30 15:25
     * @Description: 删除文件
     */
    public static void deleteFileMenu(byte[][] disk, int row, int i) {
        byte check8= (byte) (disk[row][i*8+5]&8);
        byte check4= (byte) (disk[row][i*8+5]&4);
        if(check4==4) /**0100**/
        {
            deleteFile(disk,disk[row][i*8+6]);
        }
        else if(check8==8) /**1000**/
        {
            deleteRow(disk,disk[row][i*8+6]);
        }
        for(int j=0;j<8;j++)
        {
            disk[row][i*8+j]=0;
        }
    }
    public static void deleteFile(byte[][] disk,int index) /**删文件**/
    {
        if(index<2)
        {
            return;
        }
        System.out.println(index);
        deleteFile(disk,findNext(disk,index));
        for(int i=0;i<64;i++)
        {
            disk[index][i]=0;
        }
        disk[0][index]=0;
    }
    public static int findNext(byte[][] disk, int index)
    {
        if(disk[0][index]!=0&&disk[0][index]!=-1)
        {
            return disk[0][index];
        }
        else
        {
            return -1;
        }
    }
    public static void deleteRow(byte[][] disk,int index)/**删除一行**/
    {
        if(index<2)
        {
            return;
        }
        System.out.println("Now Block:"+index);
        for(int i=0;i<8;i++)
        {
            byte check8= (byte) (disk[index][i*8+5]&8);
            byte check4= (byte) (disk[index][i*8+5]&4);
            if(check4==4) /**0100**/
            {
                System.out.println("file:"+disk[index][i*8+6]);
                deleteFile(disk,disk[index][i*8+6]);
            }
            else if(check8==8) /**1000**/
            {
                System.out.println("document:"+disk[index][i*8+6]);
                deleteRow(disk,disk[index][i*8+6]);
                deleteDoc(disk,disk[index][i*8+6]);
            }

        }
        deleteDoc(disk,index); /**删除自身**/
    }

    public static void deleteDoc(byte[][] disk,int index) /**删目录**/
    {
        if(index<2)
        {
            return;
        }
        for(int i=0;i<64;i++)
        {
            disk[index][i]=0;
        }
        disk[0][index]=0;
    }

    /**
     * @author lt4
     * @createtime 2019年11月20日20:08:00
     * 无敌delete算法
     */
    public static void deleteFile2(byte[][] disk,int row,int index){
        if(row<2)return;
        int next;//删除 文件
        int cur=disk[row][index*8+6];//指向下一个目录/ 或者 文件
        if(disk[row][index*8+5]==8){//目录
            for(int i=0;i<4;i++){
                //next=disk[cur][i+6];//这一行的 所有文件
                deleteFile2(disk,cur,i);
            }
        }else if(disk[row][index*8+5]==4){//文件
            System.out.println(cur);
            while(true){
                if(cur==-1){
                    break;
                }
                for(int i=0;i<32;i++){
                    disk[cur][i]=0;
                }
                next=disk[cur/32][cur%32];
                disk[cur/32][cur%32]=0;
                cur=next;
            }
        }

        //当前 这一段 清零
        for(int i=0;i<8;i++){
            disk[row][index*8+i]=0;
        }
        //释放FAT内存
        if(row!=2)disk[row/32][row%32]=0;

    }


    /**
     * @Author: ginenn
     * @Date: 2019/11/30 15:25
     * @Description: 在相应块号的磁盘块中获得并返回所有的文件
     */
    public static List<Item> getFileItem(byte[][] disk,int row){
        List<Item> list=new ArrayList<>();

        for(int i=0;i<64;i=i+8){
            if(disk[row][i+6]!=0){
                Item item=new Item();
                byte [] attr = new byte[8];
                for(int j = 0; j < 8; j++){
                    attr[j] = disk[row][j+i];
                }
                item.setAttr(attr);
                list.add(item);
            }
        }

        return list;
    }

    /**
     * @Author: ginenn
     * @Date: 2019/11/21 22:38
     * @Description: 根据需要创建文件的路径和目录属性来创建文件，同时输出创建结果
     */
    public static boolean createFile(byte[][] disk, String path, byte attributes){
        String [] str = path.split("/");
        if(str.length < 2 || !str[0].equals("C:")){
            System.out.println("1 文件路径名错误，文件创建失败");
            return false;
        }
        for(int i = 0; i < str.length; i++){
            if(str[i].length() > 3) {
                System.out.println("2 文件路径名错误，文件创建失败");
                return false;
            }
        }
        int pos = findDiskPos(disk, str, 0, 2);
        if(pos == -1){
            System.out.println("3 文件路径名不存在，文件创建失败");
            return false;
        }
        for(int i = 0; i < 64; i += 8){
            int ok = 1;
            for(int j=0; j < str[str.length-1].length(); j++){
                if((byte)str[str.length-1].charAt(j) != disk[pos][i+j]) ok = 0;
            }
            if(str[str.length-1].length()!=3) {
                for(int k = str[str.length-1].length();k < 3;k++) {
                    if(disk[pos][i+k]!=0) {
                        ok = 0;
                    }
                }
            }

            if(ok == 1){
                System.out.println("4 文件名已存在，文件创建失败");
                return false;
            }
        }
        for(int i = 0; i < 64; i += 8){
            int ok = 1;
            for(int j=0; j<8; j++){
                if(disk[pos][i+j] != 0){
                    ok = 0;
                    break;
                }
            }
            if(ok == 1){
                for(int j = 0; j < str[str.length-1].length(); j++)
                    disk[pos][i+j] = (byte)str[str.length-1].charAt(j);
                disk[pos][i+3] = disk[pos][4] = (byte)' ';
                disk[pos][i+5] = attributes;
                disk[pos][i+6] = (byte)DiskUtil.getFreeBlock(disk);
                if(attributes==8){
                    disk[pos][i+7]=0;
                }else if (attributes==4){
                    disk[pos][i+7]=1;
                    disk[disk[pos][i+6]][0]=35;
                }
                System.out.println("文件创建成功");
                return true;
            }
        }
        System.out.println("当前目录无法再创建文件，文件创建失败");
        return  false;
    }

    /**
     * @Author: ginenn
     * @Date: 2019/11/21 22:17
     * @Description: 创建文件时调用该递归方法，如果文件路径错误则返回-1，否则返回所在直接父目录的磁盘块的位置
     * @param disk: 磁盘
     * @param str: 文件路径名数组
     * @param k: 当前递归到的树型目录的层数
     * @param cur: 当前递归到的树型目录所在层的指向其子目录的所在磁盘的指针
     */
    public static int findDiskPos(byte[][] disk, String [] str, int k, int cur){
        if(k == str.length-2) return cur;
        int pos = -1;
        for(int i = 0; i < 64; i += 8){
            int ok = 1;
            for(int j=0; j < str[k+1].length(); j++){
                if((byte)str[k+1].charAt(j) != disk[cur][i+j]) ok = 0;
            }
            if(ok == 1){
                pos = disk[cur][i+6];
                break;
            }
        }
        if(pos == -1) return -1;
        else return findDiskPos(disk, str, k+1, pos);
    }



    /**
     * @author lts
     * @CreateTime 2019年11月20日13:00:00
     * @param file:传入打开窗口的 文件 需要先创一个offile
     * 得到文件值
     * */
    public static String getFileText(byte[][] disk, OFFile file) {
        String str="";
        int cur=file.getRead().getDnum();
        int j=0;
        while(true){
            if(disk[cur][j]==35){// #
                break;
            }
            str+=(char)disk[cur][j++];
            if(j==64){
                cur=disk[cur/64][cur%64];
                j=0;
            }

        }
        System.out.println(str);
        return str;
    }




    /**
     * @author lts
     * @CreateTime 2019年11月20日15:20:03
     * @param  file:OFFile文件 用于打开窗口传值 需要先创一个offile
     *
     * 追加字符串
     * */
    public static int updateFileText(byte[][] disk , OFFile file, String str){
        str+="#";
        int cur=file.getWrite().getDnum();
        int next,addBlock=0;
        int j=file.getWrite().getBnum();
        //得到多出的str字符
        if((str.length()<(file.getLength()-1)*64+j)){
            return 1;
        }else{
            str=str.substring((file.getLength()-1)*64+j,str.length());
            byte[] bytes=str.getBytes();
            for(int i=0;i<str.length();i++){
                disk[cur][j++]=bytes[i];
                if(j==64){
                    //得到新盘块
                    next=DiskUtil.getFreeBlock(disk);
                    disk[next/64][next%64]=-1;
                    //目前 cur指向 next
                    disk[cur/64][cur%64]= (byte) next;
                    cur=next;
                    //更新添加多少新的盘块
                    addBlock++;

                    j=0;
                }
            }
            //更新
            file.getWrite().setBnum(j);
            file.getWrite().setDnum(cur);
            file.setLength(file.getLength()+addBlock);

            return 1;
        }

    }





    //以下为 过期方法 测试可以调用
    /**
     * @author lts
     * @CreateTime 2019年11月20日13:00:00
     * @param index:传入需要更新的 盘块号 会自动换行追加
     * 得到文件值
     * */
    public static int updateFileText(byte[][] disk ,int index,String str){
        int j=0;//一行的第几个出现 #
        int cur=index;//当前 block
        int len=0;//需要忽略的行数
        str+="#";//结束符
        while (true){
            if(disk[cur][j]==35){// #
                break;
            }
            j++;
            if(j==64){
                //找到下一个Fat 的next
                cur=disk[cur/64][cur%64];
                len++;
                j=0;
                if(cur==-1){//第一次插入
                    cur=index;
                    j=len=0;
                    break;
                }

            }
        }
        //剪切
        int addBlock=0;//记录新增的文件长度
        str=str.substring(len*64+j,str.length());
        byte[] bytes=str.getBytes();
        for(int i=0;i<bytes.length;i++){
            disk[cur][j++]=bytes[i];
            if(j==64){
                //得到一个空闲block
                int next=DiskUtil.getFreeBlock(disk);
                //cur指向next
                disk[cur/64][cur%64]= (byte) next;
                //next变-1
                disk[next/64][next%64]=-1;
                cur=next;
                j=0;
                addBlock++;
            }

        }
        return addBlock;
    }


    /**
     * @author lts
     * @CreateTime 2019年11月20日13:00:00
     * @param index:需要传入的读取文件的起始 盘块 会自己读取
     * 得到文件值
     * */
    public static String getFileText(byte[][] disk, int index){
        int j=0,cur=index;
        String str="";
        while(true){
            if(disk[cur][j]==35){// #
                break;
            }
            char ch= (char) disk[cur][j++];
            str+=ch+" ";
            if(j==64){
                //找到下一个Fat 的next
                cur=disk[cur/64][cur%64];
                j=0;
            }
        }
        return str;
    }



    /**
     * @Author: 水虎
     * @Date: 2019/11/21 22:17
     */
    //-1表示没找到
    static int location = -1;

    //将byte数组打印
    public static void showByteArr(byte[] b) {
        System.out.println(Arrays.toString(b));
    }

    //判断前3个字符串是否相等
    public static boolean isEqual(byte[] b,byte[] b2) {
        int jud = 0;
        for(int i = 0;i < 3;i++) {
            if(b[i]!=b2[i]) {
                jud = 1;
                break;
            }
        }

        if(jud==0) {
            return true;
        }
        else {
            return false;
        }

    }

    //根据路径找到盘块号
    public static int findDisk(String path,byte[][] disk) {
        //目录路径根据'/'拆为string数组
        String[] catalogArr = path.split("[:/+]");
        for(int i = 2;i < catalogArr.length;i++) {
            catalogArr[i-2] = catalogArr[i];
        }
        int count = 0;
        int len = 0;
        boolean isFind = true;
        byte[] b = new byte[3];
        byte[] b2 = new byte[3];
        byte[] b3 = new byte[3];

        //根目录位置
        int x = 2;
        int y = 0;
        while(true) {
            //将路径赋值到b
            for(int i = 0;i < catalogArr[count].getBytes().length;i++) {
                b[i] = catalogArr[count].getBytes()[i];
            }
            //若长度不足3，则用0补全b数组
            for(int i = catalogArr[count].getBytes().length;i < 3;i++) {
                b[i] = 0;
            }
            //
            //System.out.print("路径名:");
            //showByteArr(b);

            //将盘块前三位放入b2准备比较
            for(int i = 0;i < 3;i++) {
                b2[i] = disk[x][y+i];
            }
            //
            //System.out.print("磁盘名:");
            //showByteArr(b2);

            //判断路径与盘块前三位的名字是否相等
            if(isEqual(b,b2)) {
                count++;
                if(count==catalogArr.length-2) {
                    location = y;
                    System.out.println("文件在第"+x+"号盘块,下标是"+y);
                    break;
                }
                x = disk[x][y+6];
                y=0;
                //超出范围了还没找到
                if(x>128) {
                    isFind = false;
                    break;
                }
            }
            else {
                //
                if(y<64) {
                    y = y+8;
                    //System.out.println("找盘块下一个位置:   "+"位置"+y);
                    continue;
                }
                else {
                    isFind = false;
                    break;
                }
            }
        }
        /*
         *  若找到，返回盘块位置
         *  若找不到，返回-1
         */
        if(isFind) {
            return x;
        }
        else {
            return -1;
        }
    }

    //判断长度为8的byte类型数组是否为全0
    public static boolean diskIsEmpty(byte[] b) {
        boolean jud = true;

        for(int i = 0;i < 8;i++) {
            if(b[i]!=0) {
                jud = false;
                break;
            }
        }
        return jud;
    }

    //计算磁盘剩余容量
    public static double calculateMemory(byte[][] disk) {
        double result = 0;
        int x = 1;
        int y = 0;
        byte[] diskPart= new byte[8];
        int countFull = 4;//第一盘块已经满了
        int countEmpty = 0;
        int diskMemory = 40;

        while(x<10) {
            //1
            for(int i = 0;i < 8;i++) {
                diskPart[i] = disk[x][y+i];
            }

            if(diskIsEmpty(diskPart)) {
                countEmpty++;
            }
            else {
                countFull++;
            }
            //System.out.print(diskIsEmpty(diskPart)+"  ");

            //2
            for(int i = 0;i < 8;i++) {
                diskPart[i] = disk[x][y+i+8];
            }

            if(diskIsEmpty(diskPart)) {
                countEmpty++;
            }
            else {
                countFull++;
            }
            //System.out.print(diskIsEmpty(diskPart)+"  ");

            //3
            for(int i = 0;i < 8;i++) {
                diskPart[i] = disk[x][y+i+16];
            }

            if(diskIsEmpty(diskPart)) {
                countEmpty++;
            }
            else {
                countFull++;
            }
            //System.out.print(diskIsEmpty(diskPart)+"  ");

            //4
            for(int i = 0;i < 8;i++) {
                diskPart[i] = disk[x][y+i+24];
            }

            if(diskIsEmpty(diskPart)) {
                countEmpty++;
            }
            else {
                countFull++;
            }
            //System.out.println(diskIsEmpty(diskPart)+"  ");


            x++;
        }

        result = (((double)countFull)/((double)diskMemory));
        return result;
    }

    //封装搜索的返回值
    public static SearchedFile findFile(String path,byte[][] disk) {
        int diskNumber = findDisk(path, disk);

        if(location==-1) {
            System.out.println("文件不存在");
            return null;
        }
        else {
            if(diskNumber==-1)
            {
                return null;
            }
            else
            {
                byte[] fileItem = new byte[8];
                Item item = new Item();
                for(int i = 0;i < 8;i++) {
                    fileItem[i] = disk[diskNumber][location+i];
                }
                item.setAttr(fileItem);
                SearchedFile file = new SearchedFile(diskNumber,location,item);
                return file;
            }

        }
    }



}
